home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / misc1 / iv26_w30.zip / EXAMPLES / IDRAW / EDITOR.C < prev    next >
C/C++ Source or Header  |  1992-02-05  |  36KB  |  1,374 lines

  1. /*
  2.  * Copyright (c) 1987, 1988, 1989 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and its
  5.  * documentation for any purpose is hereby granted without fee, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of Stanford not be used in advertising or
  9.  * publicity pertaining to distribution of the software without specific,
  10.  * written prior permission.  Stanford makes no representations about
  11.  * the suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  *
  14.  * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  19.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  20.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21.  */
  22.  
  23. /* $Header: editor.c,v 1.24 90/02/05 16:16:53 linton Exp $ */
  24.  
  25. /*
  26.  * implements class Editor.
  27.  */
  28.  
  29. #include "dialogbox.h"
  30. #include "drawing.h"
  31. #include "drawingview.h"
  32. #include "editor.h"
  33. #include "history.h"
  34. #include "idraw.h"
  35. #include "listchange.h"
  36. #include "listselectn.h"
  37. #include "rubbands.h"
  38. #include "slellipses.h"
  39. #include "sllines.h"
  40. #include "slpolygons.h"
  41. #include "slsplines.h"
  42. #include "sltext.h"
  43. #include "state.h"
  44. #include "tedit.h"
  45. #include "version.h"
  46. #include <InterViews/event.h>
  47. #include <InterViews/transformer.h>
  48. #include <stdio.h>
  49. #include <mem.h>
  50.  
  51. /*
  52.  * Editor creates its history and dialog boxes.
  53.  */
  54.  
  55. Editor::Editor (Interactor* i) {
  56.     history = new History(i);
  57.     numberofdialog = new Messager(i);
  58.     opendialog = new Finder(i, "Enter name of drawing to open:");
  59.     overwritedialog= new Confirmer(i, "already exists; overwrite?");
  60.     precmovedialog = new NamerNUnit(i,"Enter X and Y movement:",
  61.                    "points", "pixels");
  62.     precrotdialog = new Namer(i, "Enter rotation in degrees:");
  63.     precscaledialog = new Namer(i, "Enter X and Y scaling:");
  64.     printdialog = new Namer(i, "Enter print command:");
  65.     readonlydialog = new Messager(i, "Drawing is readonly.");
  66.     revertdialog = new Confirmer(i, "Really revert to original?");
  67.     saveasdialog = new Finder(i, "Enter a name for this drawing:");
  68.     savecurdialog = new Confirmer(i, "Save current drawing?");
  69.     spacingdialog = new NamerNUnit(i, "Enter grid spacing:",
  70.                    "points", "pixels");
  71.     versiondialog = new Messager(i, version);
  72.  
  73.     drawing = nil;
  74.     drawingview = nil;
  75.     state = nil;
  76. }
  77.  
  78. /*
  79.  * ~Editor frees storage allocated for its history and dialog boxes.
  80.  */
  81.  
  82. Editor::~Editor () {
  83.     delete history;
  84.     delete numberofdialog;
  85.     delete opendialog;
  86.     delete overwritedialog;
  87.     delete precmovedialog;
  88.     delete precrotdialog;
  89.     delete precscaledialog;
  90.     delete printdialog;
  91.     delete readonlydialog;
  92.     delete revertdialog;
  93.     delete saveasdialog;
  94.     delete savecurdialog;
  95.     delete spacingdialog;
  96.     delete versiondialog;
  97. }
  98.  
  99. /*
  100.  * Define access functions to set members' values.  Only Idraw sets
  101.  * their values.
  102.  */
  103.  
  104. void Editor::SetDrawing (Drawing* d) {
  105.     drawing = d;
  106. }
  107.  
  108. void Editor::SetDrawingView (DrawingView* dv) {
  109.     drawingview = dv;
  110. }
  111.  
  112. void Editor::SetState (State* s) {
  113.     state = s;
  114. }
  115.  
  116. /*
  117.  * HandleSelect lets the user pick a Selection if one's under the
  118.  * mouse, otherwise it lets the user manipulate a rubber rectangle to
  119.  * enclose the Selection he wants to pick.  HandleSelect clears all
  120.  * previous Selections unless the user holds down the shift key to
  121.  * extend the Selections being made.
  122.  */
  123.  
  124.  
  125. void Editor::HandleSelect (Event& e) {
  126.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  127.     if (!e.shift) {        /* replacing previous Selections */
  128.     drawingview->EraseHandles();
  129.     if (pick != nil) {
  130.         drawing->Select(pick);
  131.     } else {
  132.         RubberRect* rubberrect =
  133.         new RubberRect(nil, nil, e.x, e.y, e.x, e.y);
  134.         drawingview->Manipulate(e, rubberrect, UpEvent, false);
  135.         Coord l, b, r, t;
  136.         rubberrect->GetCurrent(l, b, r, t);
  137.         delete rubberrect;
  138.  
  139.         SelectionList* picklist= drawing->PickSelectionsWithin(l, b, r, t);
  140.         drawing->Select(picklist);
  141.         delete picklist;
  142.     }
  143.     } else {            /* extending Selections */
  144.     if (pick != nil) {
  145.         drawingview->ErasePickedHandles(pick);
  146.         drawing->Extend(pick);
  147.     } else {
  148.         RubberRect* rubberrect =
  149.         new RubberRect(nil, nil, e.x, e.y, e.x, e.y);
  150.         drawingview->Manipulate(e, rubberrect, UpEvent, false);
  151.         Coord l, b, r, t;
  152.         rubberrect->GetCurrent(l, b, r, t);
  153.         delete rubberrect;
  154.  
  155.         SelectionList* picklist= drawing->PickSelectionsWithin(l, b, r, t);
  156.         drawingview->ErasePickedHandles(picklist);
  157.         drawing->Extend(picklist);
  158.         delete picklist;
  159.     }
  160.     }
  161.     drawingview->DrawHandles();
  162. }
  163.  
  164. /*
  165.  * HandleMove lets the user manipulate a sliding rectangle enclosing
  166.  * the Selections and moves them the same way when the user releases
  167.  * the button.
  168.  */
  169.  
  170. void Editor::HandleMove (Event& e) {
  171.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  172.     if (pick != nil) {
  173.     drawingview->EraseUngraspedHandles(pick);
  174.     drawing->Grasp(pick);
  175.     drawingview->DrawHandles();
  176.  
  177.     Coord l, b, r, t;
  178.     drawing->GetBox(l, b, r, t);
  179.     state->Constrain(e.x, e.y);
  180.     SlidingRect* slidingrect =
  181.         new SlidingRect(nil, nil, l, b, r, t, e.x, e.y);
  182.     drawingview->Manipulate(e, slidingrect, UpEvent);
  183.     Coord nl, nb, nr, nt;
  184.     slidingrect->GetCurrent(nl, nb, nr, nt);
  185.     delete slidingrect;
  186.  
  187.     if (nl != l || nb != b) {
  188.         float x0, y0, x1, y1;
  189.         Transformer t;
  190.         drawing->GetPictureTT(t);
  191.         t.InvTransform(float(l), float(b), x0, y0);
  192.         t.InvTransform(float(nl), float(nb), x1, y1);
  193.         Do(new MoveChange(drawing, drawingview, x1 - x0, y1 - y0));
  194.     }
  195.     }
  196. }
  197.  
  198. /*
  199.  * HandleScale lets the user manipulate a scaling rectangle enclosing
  200.  * the picked Selection and scales the Selections to the new scale
  201.  * when the user releases the button.
  202.  */
  203.  
  204. void Editor::HandleScale (Event& e) {
  205.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  206.     if (pick != nil) {
  207.     drawingview->EraseUngraspedHandles(pick);
  208.     drawing->Grasp(pick);
  209.     drawingview->DrawHandles();
  210.  
  211.     float l, b, r, t;
  212.     pick->GetBounds(l, b, r, t);
  213.     float cx, cy;
  214.     pick->GetCenter(cx, cy);
  215.     ScalingRect* scalingrect =
  216.         new ScalingRect(nil, nil, round(l), round(b), round(r), round(t),
  217.                 round(cx), round(cy));
  218.     drawingview->Manipulate(e, scalingrect, UpEvent);
  219.     float scale = scalingrect->CurrentScaling();
  220.     delete scalingrect;
  221.  
  222.     if (scale != 0) {
  223.         Do(new ScaleChange(drawing, drawingview, scale, scale));
  224.     }
  225.     }
  226. }
  227.  
  228. /*
  229.  * HandleStretch lets the user manipulate a stretching rectangle
  230.  * enclosing the picked Selection and stretches the Selections the
  231.  * same way when the user releases the button.
  232.  */
  233.  
  234. void Editor::HandleStretch (Event& e) {
  235.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  236.     if (pick != nil) {
  237.     drawingview->EraseUngraspedHandles(pick);
  238.     drawing->Grasp(pick);
  239.     drawingview->DrawHandles();
  240.  
  241.     float l, b, r, t;
  242.     pick->GetBounds(l, b, r, t);
  243.     IStretchingRect* istretchingrect = new
  244.         IStretchingRect(nil, nil, round(l), round(b), round(r), round(t));
  245.     drawingview->Manipulate(e, istretchingrect, UpEvent);
  246.     float stretch = istretchingrect->CurrentStretching();
  247.     Alignment side = istretchingrect->CurrentSide(drawing->GetLandscape());
  248.     delete istretchingrect;
  249.  
  250.     if (stretch != 0) {
  251.         Do(new StretchChange(drawing, drawingview, stretch, side));
  252.     }
  253.     }
  254. }
  255.  
  256. /*
  257.  * HandleRotate lets the user manipulate a rotating rectangle
  258.  * enclosing the picked Selection and rotates the Selections the same
  259.  * way when the user releases the button.
  260.  */
  261.  
  262. void Editor::HandleRotate (Event& e) {
  263.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  264.     if (pick != nil) {
  265.     drawingview->EraseUngraspedHandles(pick);
  266.     drawing->Grasp(pick);
  267.     drawingview->DrawHandles();
  268.  
  269.     Coord l, b, r, t;
  270.     pick->GetBox(l, b, r, t);
  271.     float cx, cy;
  272.     pick->GetCenter(cx, cy);
  273.     state->Constrain(e.x, e.y);
  274.     RotatingRect* rotatingrect =
  275.         new RotatingRect(nil, nil, l, b, r, t, round(cx), round(cy),
  276.                  e.x, e.y);
  277.     drawingview->Manipulate(e, rotatingrect, UpEvent);
  278.     float angle = rotatingrect->CurrentAngle();
  279.     delete rotatingrect;
  280.  
  281.     if (angle != 0) {
  282.         Do(new RotateChange(drawing, drawingview, angle));
  283.     }
  284.     }
  285. }
  286.  
  287. /*
  288.  * HandleReshape lets the user reshape an already existing Selection
  289.  * and replaces the Selection with the reshaped Selection.  Text
  290.  * Selections "reshape" themselves using different code below.
  291.  */
  292.  
  293. void Editor::HandleReshape (Event& e) {
  294.     Selection* pick = drawing->PickSelectionShapedBy(e.x, e.y);
  295.     if (pick != nil) {
  296.     drawingview->EraseHandles();
  297.     drawing->Select(pick);
  298.     drawingview->DrawHandles();
  299.     Selection* reshapedpick = nil;
  300.     if (pick->IsA(TEXTSELECTION)) {
  301.         int len;
  302.         const char* text = ((TextSelection*) pick)->GetOriginal(len);
  303.         TextEdit* textedit = new TextEdit(text, len);
  304.         drawingview->EraseHandles();
  305.         drawingview->Edit(e, textedit, pick);
  306.         text = textedit->GetText(len);
  307.         reshapedpick = new TextSelection(text, len, pick);
  308.         delete textedit;
  309.     } else {
  310.         Rubberband* shape = pick->CreateShape(e.x, e.y);
  311.         drawingview->Manipulate(e, shape, UpEvent);
  312.         reshapedpick = pick->GetReshapedCopy();
  313.     }
  314.     if (reshapedpick != nil) {
  315.         Do(new ReplaceChange(drawing, drawingview, pick, reshapedpick));
  316.     }
  317.     }
  318. }
  319.  
  320. /*
  321.  * HandleMagnify lets the user manipulate a rubber rectangle and
  322.  * expands the given area to fill the view.
  323.  */
  324.  
  325. void Editor::HandleMagnify (Event& e) {
  326.     RubberRect* rubberrect = NewRubberRectOrSquare(e);
  327.     drawingview->Manipulate(e, rubberrect, UpEvent, false);
  328.     Coord fx, fy;
  329.     rubberrect->GetCurrent(fx, fy, e.x, e.y);
  330.     delete rubberrect;
  331.  
  332.     drawingview->Magnify(fx, fy, e.x, e.y);
  333. }
  334.  
  335. /*
  336.  * HandleText lets the user type some text and creates a new
  337.  * TextSelection when the user finishes typing the text.  It must
  338.  * clear the selection list because DrawingView will redraw the
  339.  * handles obscured by the TextEdit if the list's not empty.
  340.  */
  341.  
  342. void Editor::HandleText (Event& e) {
  343.     drawingview->EraseHandles();
  344.     drawing->Clear();
  345.     TextEdit* textedit = new TextEdit;
  346.     drawingview->Edit(e, textedit);
  347.     int len;
  348.     const char* text = textedit->GetText(len);
  349.     if (len > 0) {
  350.     drawing->Select(new TextSelection(text, len, state->GetTextGS()));
  351.     Do(new AddChange(drawing, drawingview));
  352.     }
  353.     delete textedit;
  354. }
  355.  
  356. /*
  357.  * HandleLine lets the user manipulate a rubber line and creates
  358.  * a LineSelection when the user releases the button.
  359.  */
  360.  
  361. void Editor::HandleLine (Event& e) {
  362.     drawingview->EraseHandles();
  363.     state->Constrain(e.x, e.y);
  364.     RubberLine* rubberline = NewRubberLineOrAxis(e);
  365.     drawingview->Manipulate(e, rubberline, UpEvent);
  366.     Coord x0, y0, x1, y1;
  367.     rubberline->GetCurrent(x0, y0, x1, y1);
  368.     delete rubberline;
  369.  
  370.     if (x0 != x1 || y0 != y1) {
  371.     drawing->Select(
  372.         new LineSelection(x0, y0, x1, y1, state->GetGraphicGS())
  373.     );
  374.     Do(new AddChange(drawing, drawingview));
  375.     }
  376. }
  377.  
  378. /*
  379.  * HandleMultiLine lets the user draw a series of connected lines and
  380.  * creates a MultiLineSelection when the user presses the middle
  381.  * button.
  382.  */
  383.  
  384. void Editor::HandleMultiLine (Event& e) {
  385.     Coord* x;
  386.     Coord* y;
  387.     int n;
  388.  
  389.     drawingview->EraseHandles();
  390.     InputVertices(e, x, y, n);
  391.  
  392.     if (n != 2 || x[0] != x[1] || y[0] != y[1]) {
  393.     drawing->Select(
  394.         new MultiLineSelection(x, y, n, state->GetGraphicGS())
  395.     );
  396.     Do(new AddChange(drawing, drawingview));
  397.     }
  398. }
  399.  
  400. /*
  401.  * HandleBSpline lets the user draw a series of connected lines and
  402.  * creates a BSplineSelection when the user presses the middle button.
  403.  */
  404.  
  405. void Editor::HandleBSpline (Event& e) {
  406.     Coord* x;
  407.     Coord* y;
  408.     int n;
  409.  
  410.     drawingview->EraseHandles();
  411.     InputVertices(e, x, y, n);
  412.  
  413.     if (n != 2 || x[0] != x[1] || y[0] != y[1]) {
  414.     drawing->Select(
  415.         new BSplineSelection(x, y, n, state->GetGraphicGS())
  416.     );
  417.     Do(new AddChange(drawing, drawingview));
  418.     }
  419. }
  420.  
  421. /*
  422.  * HandleEllipse lets the user manipulate a rubber ellipse and creates
  423.  * an EllipseSelection when the user releases the button.
  424.  */
  425.  
  426. void Editor::HandleEllipse (Event& e) {
  427.     drawingview->EraseHandles();
  428.     state->Constrain(e.x, e.y);
  429.     RubberEllipse* rubberellipse = NewRubberEllipseOrCircle(e);
  430.     drawingview->Manipulate(e, rubberellipse, UpEvent);
  431.     Coord cx, cy, rx, ry;
  432.     int xr, yr;
  433.     rubberellipse->GetCurrent(cx, cy, rx, ry);
  434.     rubberellipse->CurrentRadii(xr, yr);
  435.     delete rubberellipse;
  436.  
  437.     if (xr > 0 || yr > 0) {
  438.     drawing->Select(
  439.         new EllipseSelection(cx, cy, xr, yr, state->GetGraphicGS())
  440.             );
  441.     Do(new AddChange(drawing, drawingview));
  442.     }
  443. }
  444.  
  445. /*
  446.  * HandleRect lets the user manipulate a rubber rectangle and creates
  447.  * a RectSelection when the user releases the button.
  448.  */
  449.  
  450. void Editor::HandleRect (Event& e) {
  451.     drawingview->EraseHandles();
  452.     state->Constrain(e.x, e.y);
  453.     RubberRect* rubberrect = NewRubberRectOrSquare(e);
  454.     drawingview->Manipulate(e, rubberrect, UpEvent);
  455.     Coord l, b, r, t;
  456.     rubberrect->GetCurrent(l, b, r, t);
  457.     delete rubberrect;
  458.  
  459.     if (l != r || b != t) {
  460.     drawing->Select(new RectSelection(l, b, r, t, state->GetGraphicGS()));
  461.     Do(new AddChange(drawing, drawingview));
  462.     }
  463. }
  464.  
  465. /*
  466.  * HandlePolygon lets the user draw a series of connected lines and
  467.  * creates a PolygonSelection when the user presses the middle button.
  468.  */
  469.  
  470. void Editor::HandlePolygon (Event& e) {
  471.     Coord* x;
  472.     Coord* y;
  473.     int n;
  474.  
  475.     drawingview->EraseHandles();
  476.     InputVertices(e, x, y, n);
  477.  
  478.     if (n != 2 || x[0] != x[1] || y[0] != y[1]) {
  479.     drawing->Select(new PolygonSelection(x, y, n, state->GetGraphicGS()));
  480.     Do(new AddChange(drawing, drawingview));
  481.     }
  482. }
  483.  
  484. /*
  485.  * HandleClosedBSpline lets the user draw a series of connected lines
  486.  * and creates a ClosedBSplineSelection when the user presses the
  487.  * middle button.
  488.  */
  489.  
  490. void Editor::HandleClosedBSpline (Event& e) {
  491.     Coord* x;
  492.     Coord* y;
  493.     int n;
  494.  
  495.     drawingview->EraseHandles();
  496.     InputVertices(e, x, y, n);
  497.  
  498.     if (n != 2 || x[0] != x[1] || y[0] != y[1]) {
  499.     drawing->Select(
  500.         new ClosedBSplineSelection(x, y, n, state->GetGraphicGS())
  501.     );
  502.     Do(new AddChange(drawing, drawingview));
  503.     }
  504. }
  505.  
  506. /*
  507.  * New offers to write an unsaved drawing and creates a new empty
  508.  * drawing if the save succeeds or the user refuses the offer.
  509.  */
  510.  
  511. void Editor::New () {
  512.     boolean successful = OfferToSave();
  513.     if (successful) {
  514.     drawing->ClearPicture();
  515.     Reset(nil);
  516.     }
  517. }
  518.  
  519. /*
  520.  * Revert rereads the drawing from its file.  It asks for confirmation
  521.  * before reverting an unsaved drawing.
  522.  */
  523.  
  524. void Editor::Revert () {
  525.     const char* name = state->GetDrawingName();
  526.     if (name != nil) {
  527.     char response = revertdialog->Confirm();
  528.     if (response == 'y') {
  529.         boolean successful = drawing->ReadPicture(name, state);
  530.         if (successful) {
  531.         Reset(name);
  532.         } else {
  533.         savecurdialog->
  534.             SetWarning("couldn't revert! (file nonexistent?)");
  535.         Open();
  536.         }
  537.     }
  538.     }
  539. }
  540.  
  541. /*
  542.  * Open reads a drawing from the given file.  If it fails, it calls
  543.  * the interactive Open to ask the user to type another name.
  544.  */
  545.  
  546. void Editor::Open (const char* name) {
  547.     boolean successful = drawing->ReadPicture(name, state);
  548.     if (successful) {
  549.     Reset(name);
  550.     } else {
  551.     opendialog->SetTitle("Open failed!");
  552.     Open();
  553.     }
  554. }
  555.  
  556. /*
  557.  * Open prompts for a file name and reads a drawing from that file.
  558.  * It offers to save an unsaved drawing and it keeps trying to read a
  559.  * drawing until it succeeds or the user cancels the command.
  560.  */
  561.  
  562. void Editor::Open () {
  563.     boolean successful = OfferToSave();
  564.     if (successful) {
  565.     const char* name = nil;
  566.     for (;;) {
  567.         name = opendialog->Find();
  568.         if (name == nil) {
  569.         break;
  570.         }
  571.         boolean successful = drawing->ReadPicture(name, state);
  572.         if (successful) {
  573.         Reset(name);
  574.         break;
  575.         } else {
  576.         opendialog->SetTitle("Open failed!");
  577.         }
  578.     }
  579.     }
  580. }
  581.  
  582. /*
  583.  * Save writes the drawing to the file it was read from unless there's
  584.  * no file or it can't write the drawing to that file, in which case
  585.  * it hands the job off to SaveAs.
  586.  */
  587.  
  588. void Editor::Save () {
  589.     const char* name = state->GetDrawingName();
  590.     if (name == nil) {
  591.     SaveAs();
  592.     } else if (state->GetModifStatus() == ReadOnly) {
  593.     saveasdialog->SetTitle("Can't save in read-only file!");
  594.     SaveAs();
  595.     } else {
  596.     boolean successful = drawing->WritePicture(name, state);
  597.     if (successful) {
  598.         state->SetModifStatus(Unmodified);
  599.         state->UpdateViews();
  600.     } else {
  601.         saveasdialog->SetTitle("Couldn't save!");
  602.         SaveAs();
  603.     }
  604.     }
  605. }
  606.  
  607. /*
  608.  * SaveAs prompts for a file name and writes the drawing to that file.
  609.  * It asks for confirmation before overwriting an already existing
  610.  * file and it keeps trying to write the drawing until it succeeds or
  611.  * the user cancels the command.
  612.  */
  613.  
  614. void Editor::SaveAs () {
  615.     const char* name = nil;
  616.     for (;;) {
  617.     name = saveasdialog->Find();
  618.     if (name == nil) {
  619.         break;
  620.     }
  621.     if (drawing->Exists(name)) {
  622.         overwritedialog->SetWarning("a drawing named ", name);
  623.         char response = overwritedialog->Confirm();
  624.         if (response != 'y') {
  625.         break;
  626.         }
  627.     }
  628.     boolean successful = drawing->WritePicture(name, state);
  629.     if (successful) {
  630.         state->SetDrawingName(name);
  631.         state->SetModifStatus(Unmodified);
  632.         state->UpdateViews();
  633.         break;
  634.     } else {
  635.         saveasdialog->SetTitle("Couldn't save!");
  636.     }
  637.     }
  638.     saveasdialog->SetTitle("");
  639. }
  640.  
  641. /*
  642.  * Print prompts for a print command and writes the drawing through a
  643.  * pipe to that command's standard input.  It keeps trying to print
  644.  * the drawing until it succeeds or the user cancels the command.
  645.  */
  646.  
  647. void Editor::Print () {
  648.     if (state->GetModifStatus() == Modified) {
  649.     savecurdialog->SetWarning("a broken pipe signal won't be caught");
  650.     }
  651.     boolean successful = OfferToSave();
  652.     if (successful) {
  653.     char* cmd = nil;
  654.     for (;;) {
  655.         delete cmd;
  656.         cmd = printdialog->Edit(nil);
  657.         if (cmd == nil) {
  658.         break;
  659.         }
  660.         boolean successful = drawing->PrintPicture(cmd, state);
  661.         if (successful) {
  662.         break;
  663.         } else {
  664.         printdialog->SetWarning("couldn't execute ", cmd);
  665.         }
  666.     }
  667.     delete cmd;
  668.     }
  669. }
  670.  
  671. /*
  672.  * Quit offers to save an unsaved drawing and tells Idraw to quit
  673.  * running if the save succeeds or the user refuses the offer.
  674.  */
  675.  
  676. void Editor::Quit (Event& e) {
  677.     boolean successful = OfferToSave();
  678.     if (successful) {
  679.     e.target = nil;
  680.     }
  681. }
  682.  
  683. /*
  684.  * Checkpoint writes an unsaved drawing to a temporary filename.  The
  685.  * program currently calls Checkpoint only when an X error occurs.
  686.  */
  687.  
  688. void Editor::Checkpoint () {
  689.     if (state->GetModifStatus() == Modified) {
  690.     char* path = "idraw";
  691.     boolean successful = drawing->WritePicture(path, state);
  692.     if (successful) {
  693.         fprintf(stderr, "saved drawing as \"%s\"\n", path);
  694.     } else {
  695.         fprintf(stderr, "sorry, couldn't save drawing as \"%s\"\n", path);
  696.     }
  697.     delete path;
  698.     } else {
  699.     fprintf(stderr, "drawing was unmodified, didn't save it\n");
  700.     }
  701. }
  702.  
  703. /*
  704.  * Undo undoes the last change made to the drawing.  Undo does nothing
  705.  * if all stored changes have been undone.
  706.  */
  707.  
  708. void Editor::Undo () {
  709.     history->Undo();
  710. }
  711.  
  712. /*
  713.  * Redo redoes the last undone change made to the drawing, i.e., it
  714.  * undoes an Undo.  Redo does nothing if it follows a Do.
  715.  */
  716.  
  717. void Editor::Redo () {
  718.     history->Redo();
  719. }
  720.  
  721. /*
  722.  * Cut removes the Selections and writes them to the clipboard file,
  723.  * overwriting whatever was there previously.
  724.  */
  725.  
  726. void Editor::Cut () {
  727.     Do(new CutChange(drawing, drawingview));
  728. }
  729.  
  730. /*
  731.  * Copy copies the Selections and writes them to the clipboard file,
  732.  * overwriting whatever was there previously.
  733.  */
  734.  
  735. void Editor::Copy () {
  736.     Do(new CopyChange(drawing, drawingview));
  737. }
  738.  
  739. /*
  740.  * Paste reads new Selections from the clipboard file and appends them
  741.  * to the drawing.
  742.  */
  743.  
  744. void Editor::Paste () {
  745.     Do(new PasteChange(drawing, drawingview, state));
  746. }
  747.  
  748. /*
  749.  * Duplicate duplicates the Selections and appends the new Selections
  750.  * to the drawing.
  751.  */
  752.  
  753. void Editor::Duplicate () {
  754.     Do(new DuplicateChange(drawing, drawingview));
  755. }
  756.  
  757. /*
  758.  * Delete deletes all of the Selections.
  759.  */
  760.  
  761. void Editor::Delete () {
  762.     Do(new DeleteChange(drawing, drawingview));
  763. }
  764.  
  765. /*
  766.  * SelectAll selects all of the Selections in the drawing.
  767.  */
  768.  
  769. void Editor::SelectAll () {
  770.     drawing->SelectAll();
  771.     drawingview->DrawHandles();
  772. }
  773.  
  774. /*
  775.  * FlipHorizontal flips the Selections horizontally by scaling them by
  776.  * -1 along the x axis about their centers.
  777.  */
  778.  
  779. void Editor::FlipHorizontal () {
  780.     Do(new ScaleChange(drawing, drawingview, -1, 1));
  781. }
  782.  
  783. /*
  784.  * FlipVertical flips the Selections vertically by scaling them by -1
  785.  * along the y axis about their centers.
  786.  */
  787.  
  788. void Editor::FlipVertical () {
  789.     Do(new ScaleChange(drawing, drawingview, 1, -1));
  790. }
  791.  
  792. /*
  793.  * _90Clockwise rotates the Selections 90 degrees clockwise about
  794.  * their centers.
  795.  */
  796.  
  797. void Editor::_90Clockwise () {
  798.     Do(new RotateChange(drawing, drawingview, -90.));
  799. }
  800.  
  801. /*
  802.  * _90CounterCW rotates the Selections 90 degrees counter-clockwise
  803.  * about their centers.
  804.  */
  805.  
  806. void Editor::_90CounterCW () {
  807.     Do(new RotateChange(drawing, drawingview, 90.));
  808. }
  809.  
  810. /*
  811.  * PreciseMove prompts the user for the x and y movement in units of
  812.  * points or pixels and moves the Selections that far.
  813.  */
  814.  
  815. void Editor::PreciseMove () {
  816.     char* movement = nil;
  817.     for (;;) {
  818.     delete movement;
  819.     movement = precmovedialog->Edit(nil);
  820.     if (movement == nil) {
  821.         break;
  822.     }
  823.     float xdisp, ydisp;
  824.     char unit;
  825.     if (sscanf(movement, "%f %f p%c", &xdisp, &ydisp, &unit) == 3) {
  826.         if (xdisp != 0 || ydisp != 0) {
  827.         if (unit != 'i') {
  828.             xdisp *= points;
  829.             ydisp *= points;
  830.         }
  831.         Do(new MoveChange(drawing, drawingview, xdisp, ydisp));
  832.         }
  833.         break;
  834.     } else {
  835.         precmovedialog->SetWarning("couldn't parse ", movement);
  836.     }
  837.     }
  838.     delete movement;
  839. }
  840.  
  841. /*
  842.  * PreciseScale prompts the user for the x and y scales and scales the
  843.  * Selections that much about their centers.
  844.  */
  845.  
  846. void Editor::PreciseScale () {
  847.     char* scaling = nil;
  848.     for (;;) {
  849.     delete scaling;
  850.     scaling = precscaledialog->Edit(nil);
  851.     if (scaling == nil) {
  852.         break;
  853.     }
  854.     float xscale, yscale;
  855.     if (sscanf(scaling, "%f %f", &xscale, &yscale) == 2) {
  856.         if (xscale !=0 && yscale != 0) {
  857.         Do(new ScaleChange(drawing, drawingview, xscale, yscale));
  858.         }
  859.         break;
  860.     } else {
  861.         precscaledialog->SetWarning("couldn't parse ", scaling);
  862.     }
  863.     }
  864.     delete scaling;
  865. }
  866.  
  867. /*
  868.  * PreciseRotate prompts the user for the angle and rotates the
  869.  * Selections that many degrees about their centers.
  870.  */
  871.  
  872. void Editor::PreciseRotate () {
  873.     char* rotation = nil;
  874.     for (;;) {
  875.     delete rotation;
  876.     rotation = precrotdialog->Edit(nil);
  877.     if (rotation == nil) {
  878.         break;
  879.     }
  880.     float angle;
  881.     if (sscanf(rotation, "%f", &angle) == 1) {
  882.         if (angle != 0) {
  883.         Do(new RotateChange(drawing, drawingview, angle));
  884.         }
  885.         break;
  886.     } else {
  887.         precrotdialog->SetWarning("couldn't parse ", rotation);
  888.     }
  889.     }
  890.     delete rotation;
  891. }
  892.  
  893. /*
  894.  * Group groups the Selections together.
  895.  */
  896.  
  897. void Editor::Group () {
  898.     Do(new GroupChange(drawing, drawingview));
  899. }
  900.  
  901. /*
  902.  * Ungroup ungroups each PictSelection into its component Selections.
  903.  */
  904.  
  905. void Editor::Ungroup () {
  906.     Do(new UngroupChange(drawing, drawingview));
  907. }
  908.  
  909. /*
  910.  * BringToFront brings the Selections to the front of the drawing.
  911.  */
  912.  
  913. void Editor::BringToFront () {
  914.     Do(new BringToFrontChange(drawing, drawingview));
  915. }
  916.  
  917. /*
  918.  * SendToBack sends the Selections to the back of the drawing.
  919.  */
  920.  
  921. void Editor::SendToBack () {
  922.     Do(new SendToBackChange(drawing, drawingview));
  923. }
  924.  
  925. /*
  926.  * NumberOfGraphics counts the number of graphics in the drawing and
  927.  * displays the count.
  928.  */
  929.  
  930. void Editor::NumberOfGraphics () {
  931.     int num = drawing->GetNumberOfGraphics();
  932.     if (num == 1) {
  933.     numberofdialog->SetMessage("The selections contain 1 graphic.");
  934.     } else {
  935.     char buf[50];
  936.     sprintf(buf, "The selections contain %d graphics.", num);
  937.     numberofdialog->SetMessage(buf);
  938.     }
  939.     numberofdialog->Display();
  940. }
  941.  
  942. /*
  943.  * SetBrush sets the Selections' brush and updates the views to
  944.  * display the new current brush.
  945.  */
  946.  
  947. void Editor::SetBrush (IBrush* brush) {
  948.     state->SetBrush(brush);
  949.     state->UpdateViews();
  950.     Do(new SetBrushChange(drawing, drawingview, brush));
  951. }
  952.  
  953. /*
  954.  * SetFgColor sets the Selections' foreground color and updates the
  955.  * views to display the new current foreground color.
  956.  */
  957.  
  958. void Editor::SetFgColor (IColor* fg) {
  959.     state->SetFgColor(fg);
  960.     state->UpdateViews();
  961.     Do(new SetFgColorChange(drawing, drawingview, fg));
  962. }
  963.  
  964. /*
  965.  * SetBgColor sets the Selections' background color and updates the
  966.  * views to display the new current background color.
  967.  */
  968.  
  969. void Editor::SetBgColor (IColor* bg) {
  970.     state->SetBgColor(bg);
  971.     state->UpdateViews();
  972.     Do(new SetBgColorChange(drawing, drawingview, bg));
  973. }
  974.  
  975. /*
  976.  * SetFont sets the Selections' font and updates the views to display
  977.  * the new current font.
  978.  */
  979.  
  980. void Editor::SetFont (IFont* font) {
  981.     state->SetFont(font);
  982.     state->UpdateViews();
  983.     Do(new SetFontChange(drawing, drawingview, font));
  984. }
  985.  
  986. /*
  987.  * SetPattern sets the Selections' pattern and updates the views to
  988.  * display the new current pattern.
  989.  */
  990.  
  991. void Editor::SetPattern (IPattern* pattern) {
  992.     state->SetPattern(pattern);
  993.     state->UpdateViews();
  994.     Do(new SetPatternChange(drawing, drawingview, pattern));
  995. }
  996.  
  997. /*
  998.  * AlignLeftSides aligns the rest of the Selections's left sides with
  999.  * the first Selection's left side.
  1000.  */
  1001.  
  1002. void Editor::AlignLeftSides () {
  1003.     Do(new AlignChange(drawing, drawingview, Left, Left));
  1004. }
  1005.  
  1006. /*
  1007.  * AlignRightSides aligns the rest of the Selections' right sides with
  1008.  * the first Selection's right side.
  1009.  */
  1010.  
  1011. void Editor::AlignRightSides () {
  1012.     Do(new AlignChange(drawing, drawingview, Right, Right));
  1013. }
  1014.  
  1015. /*
  1016.  * AlignBottomSides aligns the rest of the Selections' bottom sides
  1017.  * with the first Selection's bottom side.
  1018.  */
  1019.  
  1020. void Editor::AlignBottoms () {
  1021.     Do(new AlignChange(drawing, drawingview, Bottom, Bottom));
  1022. }
  1023.  
  1024. /*
  1025.  * AlignTopSides aligns the rest of the Selections' top sides with the
  1026.  * first Selection's top side.
  1027.  */
  1028.  
  1029. void Editor::AlignTops () {
  1030.     Do(new AlignChange(drawing, drawingview, Top, Top));
  1031. }
  1032.  
  1033. /*
  1034.  * AlignVertCenters aligns the rest of the Selections' vertical
  1035.  * centers with the first Selection's vertical center.
  1036.  */
  1037.  
  1038. void Editor::AlignVertCenters () {
  1039.     Do(new AlignChange(drawing, drawingview, VertCenter, VertCenter));
  1040. }
  1041.  
  1042. /*
  1043.  * AlignHorizCenters aligns the rest of the Selections' horizontal
  1044.  * centers with the first Selection's horizontal center.
  1045.  */
  1046.  
  1047. void Editor::AlignHorizCenters () {
  1048.     Do(new AlignChange(drawing, drawingview, HorizCenter, HorizCenter));
  1049. }
  1050.  
  1051. /*
  1052.  * AlignCenters aligns the rest of the Selections' centers with the
  1053.  * first Selection's center.
  1054.  */
  1055.  
  1056. void Editor::AlignCenters () {
  1057.     Do(new AlignChange(drawing, drawingview, Center, Center));
  1058. }
  1059.  
  1060. /*
  1061.  * AlignLeftToRight aligns each Selection's left side with its
  1062.  * predecessor's right side.
  1063.  */
  1064.  
  1065. void Editor::AlignLeftToRight () {
  1066.     Do(new AlignChange(drawing, drawingview, Right, Left));
  1067. }
  1068.  
  1069. /*
  1070.  * AlignRightToLeft aligns each Selection's right side with its
  1071.  * predecessor's left side.
  1072.  */
  1073.  
  1074. void Editor::AlignRightToLeft () {
  1075.     Do(new AlignChange(drawing, drawingview, Left, Right));
  1076. }
  1077.  
  1078. /*
  1079.  * AlignBottomToTop aligns each Selection's bottom side with its
  1080.  * predecessor's top side.
  1081.  */
  1082.  
  1083. void Editor::AlignBottomToTop () {
  1084.     Do(new AlignChange(drawing, drawingview, Top, Bottom));
  1085. }
  1086.  
  1087. /*
  1088.  * AlignTopToBottom aligns each Selection's top side with its
  1089.  * predecessor's bottom side.
  1090.  */
  1091.  
  1092. void Editor::AlignTopToBottom () {
  1093.     Do(new AlignChange(drawing, drawingview, Bottom, Top));
  1094. }
  1095.  
  1096. /*
  1097.  * AlignToGrid aligns the Selections' lower left corners with the
  1098.  * closest grid point.
  1099.  */
  1100.  
  1101. void Editor::AlignToGrid () {
  1102.     Do(new AlignToGridChange(drawing, drawingview));
  1103. }
  1104.  
  1105. /*
  1106.  * Reduce reduces the drawing's magnification by a factor of two.
  1107.  */
  1108.  
  1109. void Editor::Reduce () {
  1110.     drawingview->Reduce();
  1111. }
  1112.  
  1113. /*
  1114.  * Enlarge enlarges the drawing's magnification by a factor of two.
  1115.  */
  1116.  
  1117. void Editor::Enlarge () {
  1118.     drawingview->Enlarge();
  1119. }
  1120.  
  1121. /*
  1122.  * NormalSize resets the drawing's magnification.
  1123.  */
  1124.  
  1125. void Editor::NormalSize () {
  1126.     drawingview->NormalSize();
  1127. }
  1128.  
  1129. /*
  1130.  * ReduceToFit reduces the drawing's magnification enough to fit all
  1131.  * of the drawing in the window.
  1132.  */
  1133.  
  1134. void Editor::ReduceToFit () {
  1135.     drawingview->ReduceToFit();
  1136. }
  1137.  
  1138. /*
  1139.  * CenterPage scrolls the drawing so its center coincidences with the
  1140.  * window's center.
  1141.  */
  1142.  
  1143. void Editor::CenterPage () {
  1144.     drawingview->CenterPage();
  1145. }
  1146.  
  1147. /*
  1148.  * RedrawPage redraws the drawing without moving the view.
  1149.  */
  1150.  
  1151. void Editor::RedrawPage () {
  1152.     drawingview->Draw();
  1153. }
  1154.  
  1155. /*
  1156.  * GriddingOnOff toggles the grid's constraint on or off.
  1157.  */
  1158.  
  1159. void Editor::GriddingOnOff () {
  1160.     state->SetGridGravity(!state->GetGridGravity());
  1161.     state->UpdateViews();
  1162. }
  1163.  
  1164. /*
  1165.  * GridVisibleInvisible toggles the grid's visibility on or off.
  1166.  */
  1167.  
  1168. void Editor::GridVisibleInvisible () {
  1169.     state->SetGridVisibility(!state->GetGridVisibility());
  1170.     drawingview->Draw();
  1171. }
  1172.  
  1173. /*
  1174.  * GridSpacing prompts the user for the new grid spacing in units of
  1175.  * points or pixels.
  1176.  */
  1177.  
  1178. void Editor::GridSpacing () {
  1179.     static char oldspacing[50];
  1180.     sprintf(oldspacing, "%lg", state->GetGridSpacing());
  1181.     char* spacing = nil;
  1182.     for (;;) {
  1183.     delete spacing;
  1184.     spacing = spacingdialog->Edit(oldspacing);
  1185.     if (spacing == nil) {
  1186.         break;
  1187.     }
  1188.     float s;
  1189.     char unit;
  1190.     if (sscanf(spacing, "%f p%c", &s, &unit) == 2) {
  1191.         if (s > 0.) {
  1192.         state->SetGridSpacing(s, (unit == 'i'));
  1193.         if (state->GetGridVisibility() == true) {
  1194.             drawingview->Update();
  1195.         }
  1196.         }
  1197.         break;
  1198.     } else {
  1199.         spacingdialog->SetWarning("couldn't parse ", spacing);
  1200.     }
  1201.     }
  1202.     delete spacing;
  1203. }
  1204.  
  1205. /*
  1206.  * Orientation toggles the page between portrait and landscape
  1207.  * orientations.
  1208.  */
  1209.  
  1210. void Editor::Orientation () {
  1211.     state->ToggleOrientation();
  1212.     drawingview->Update();
  1213. }
  1214.  
  1215. /*
  1216.  * ShowVersion displays idraw's version level and author.
  1217.  */
  1218.  
  1219. void Editor::ShowVersion () {
  1220.     versiondialog->Display();
  1221. }
  1222.  
  1223. /*
  1224.  * Do performs a change to the drawing and updates the drawing's
  1225.  * modification status if it was unmodified.
  1226.  */
  1227.  
  1228. void Editor::Do (ChangeNode* changenode) {
  1229.     switch (state->GetModifStatus()) {
  1230.     case Unmodified:
  1231.     history->Do(changenode);
  1232.     state->SetModifStatus(Modified);
  1233.     state->UpdateViews();
  1234.     break;
  1235.     default:
  1236.     history->Do(changenode);
  1237.     break;
  1238.     }
  1239. }
  1240.  
  1241. /*
  1242.  * InputVertices lets the user keep drawing a series of connected
  1243.  * lines until the user presses a button other than the left button.
  1244.  * It returns the vertices inputted by the user.
  1245.  */
  1246.  
  1247. void Editor::InputVertices (Event& e, Coord*& xret, Coord*& yret, int& nret) {
  1248.     const int INITIALSIZE = 100;
  1249.     static int sizebuffers = 0;
  1250.     static RubberLine** rubberlines = nil;
  1251.     static Coord* x = nil;
  1252.     static Coord* y = nil;
  1253.     if (INITIALSIZE > sizebuffers) {
  1254.     sizebuffers = INITIALSIZE;
  1255.     rubberlines = new RubberLine*[sizebuffers];
  1256.     x = new Coord[sizebuffers];
  1257.     y = new Coord[sizebuffers];
  1258.     }
  1259.  
  1260.     int n = 0;
  1261.     state->Constrain(e.x, e.y);
  1262.     rubberlines[0] = nil;
  1263.     x[0] = e.x;
  1264.     y[0] = e.y;
  1265.     ++n;
  1266.  
  1267.     while (e.button == LEFTMOUSE) {
  1268.     rubberlines[n] = NewRubberLineOrAxis(e);
  1269.     e.eventType = UpEvent;
  1270.     drawingview->Manipulate(e, rubberlines[n], DownEvent, true, false);
  1271.     Coord dummy;
  1272.     rubberlines[n]->GetCurrent(dummy, dummy, e.x, e.y);
  1273.     x[n] = e.x;
  1274.     y[n] = e.y;
  1275.     ++n;
  1276.  
  1277.     if (n == sizebuffers) {
  1278.         RubberLine** oldrubberlines = rubberlines;
  1279.         Coord* oldx = x;
  1280.         Coord* oldy = y;
  1281.         sizebuffers += INITIALSIZE/2;
  1282.         rubberlines = new RubberLine*[sizebuffers];
  1283.         x = new Coord[sizebuffers];
  1284.         y = new Coord[sizebuffers];
  1285.         memmove(rubberlines, oldrubberlines, n * sizeof(RubberLine*));
  1286.         memmove(x, oldx, n * sizeof(Coord));
  1287.         memmove(y, oldy, n * sizeof(Coord));
  1288.         delete oldrubberlines;
  1289.         delete oldx;
  1290.         delete oldy;
  1291.     }
  1292.     }
  1293.  
  1294.     xret = x;
  1295.     yret = y;
  1296.     nret = n;
  1297.     for (int i = 1; i < n; i++) {
  1298.     rubberlines[i]->Erase();
  1299.     delete rubberlines[i];
  1300.     }
  1301. }
  1302.  
  1303. /*
  1304.  * NewRubberLineOrAxis creates and returns a new RubberLine or a new
  1305.  * RubberAxis depending on whether the shift key's being depressed.
  1306.  */
  1307.  
  1308. RubberLine* Editor::NewRubberLineOrAxis (Event& e) {
  1309.     return (!e.shift ? 
  1310.         new RubberLine(nil, nil, e.x, e.y, e.x, e.y) :
  1311.         new RubberAxis(nil, nil, e.x, e.y, e.x, e.y));
  1312. }
  1313.  
  1314. /*
  1315.  * NewRubberEllipseOrCircle creates and returns a new RubberEllipse or
  1316.  * a new RubberCircle depending on the shift key's state.
  1317.  */
  1318.  
  1319. RubberEllipse* Editor::NewRubberEllipseOrCircle (Event& e) {
  1320.     return (!e.shift ?
  1321.         new RubberEllipse(nil, nil, e.x, e.y, e.x, e.y) :
  1322.         new RubberCircle(nil, nil, e.x, e.y, e.x, e.y));
  1323. }
  1324.  
  1325. /*
  1326.  * NewRubberRectOrSquare creates and returns a new RubberRect or a new
  1327.  * RubberSquare depending on whether the shift key's being depressed.
  1328.  */
  1329.  
  1330. RubberRect* Editor::NewRubberRectOrSquare (Event& e) {
  1331.     return (!e.shift ? 
  1332.         new RubberRect(nil, nil, e.x, e.y, e.x, e.y) :
  1333.         new RubberSquare(nil, nil, e.x, e.y, e.x, e.y));
  1334. }
  1335.  
  1336. /*
  1337.  * OfferToSave returns true if it saves an unsaved drawing or the user
  1338.  * refuses the offer or no changes need to be saved.
  1339.  */
  1340.  
  1341. boolean Editor::OfferToSave () {
  1342.     boolean successful = false;
  1343.     if (state->GetModifStatus() == Modified) {
  1344.     char response = savecurdialog->Confirm();
  1345.     if (response == 'y') {
  1346.         Save();
  1347.         if (state->GetModifStatus() == Unmodified) {
  1348.         successful = true;
  1349.         }
  1350.     } else if (response == 'n') {
  1351.         successful = true;
  1352.     }
  1353.     } else {
  1354.     successful = true;
  1355.     }
  1356.     return successful;
  1357. }
  1358.  
  1359. /*
  1360.  * Reset redraws the view, clears the history, and resets state
  1361.  * information about the drawing's name and its modification status.
  1362.  */
  1363.  
  1364. void Editor::Reset (const char* name) {
  1365.     history->Clear();
  1366.     state->SetDrawingName(name);
  1367.     if (name != nil && !drawing->Writable(name)) {
  1368.     state->SetModifStatus(ReadOnly);
  1369.     } else {
  1370.     state->SetModifStatus(Unmodified);
  1371.     }
  1372.     state->UpdateViews();
  1373.     drawingview->Update();
  1374. }